package mi.payment.transaction;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;

import com.sunmi.pay.hardware.aidl.AidlErrorCode;
import com.sunmi.pay.hardware.aidl.SPErrorCode;
import com.sunmi.pay.hardware.aidl.bean.CardInfo;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
import com.sunmi.pay.hardware.aidlv2.bean.EMVTransDataV2;
import com.sunmi.pay.hardware.aidlv2.bean.EmvTermParamV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVListenerV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVOptV2;
import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;
import com.sunmi.pay.hardware.aidlv2.readcard.ReadCardOptV2;

import java.util.ArrayList;
import java.util.List;

import lainey.ui.dialog.ListDialog;
import lainey.ui.utils.LogUtil;
import mi.payment.CardType;
import mi.payment.Constant;
import mi.payment.MyApplication;
import mi.payment.R;
import mi.payment.bean.db.TradeData;
import mi.payment.constants.Configs;
import mi.payment.constants.Params;
import mi.payment.db.dao.PayDetail;
import mi.payment.settings.TransactionOtherOperation;
import mi.payment.ui.base.ParentActivity;
import mi.payment.utils.Config;
import mi.payment.utils.Track2Util;
import mi.payment.utils.UIUtils;
import sunmi.payment.L3.L3BroadcastHelper;
import sunmi.payment.L3.L3ErrorCode;
import sunmi.payment.ui.dialog.ForceNFCWarningDialog;

public abstract class V2BaseSwingCardActivity extends ParentActivity {

    private int mCheckCardType =
            CardType.MAGNETIC.getValue() |
                    CardType.IC.getValue() |
                    CardType.NFC.getValue();

    private EMVOptV2 mEMVOptV2;
    private ReadCardOptV2 mReadCardOptV2;

    private ListDialog mListDialog;
    private ForceNFCWarningDialog mForceNFCWarningDialog;

    public TradeData mTradeData;
    private PayDetail mPayDetail;

    public abstract void onCheckCardSuccess();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTradeData = Params.newTradeData();
        mPayDetail = mTradeData.getPayDetail();

        mEMVOptV2 = MyApplication.getInstance().mEMVOptV2;
        mReadCardOptV2 = MyApplication.getInstance().mReadCardOptV2;

        setTerminalParam();
    }

    @Override
    protected void onResume() {
        super.onResume();
        UIUtils.screenMonopoly(1);
    }

    @Override
    protected void onPause() {
        super.onPause();
        UIUtils.screenMonopoly(-1);
    }

    @Override
    public void onBackPressed() {
        abortCheckCard();
        handleCallProgram(L3ErrorCode.ERROR_TRADE_CANCEL);
        super.onBackPressed();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        dismissLoadingDialog();
        dismissForceNFCWarningDialog();
        mHandler.removeCallbacksAndMessages(null);
    }

    private static final int CHECK_CARD_FAIL = 1;
    private static final int CHECK_CARD_SUCCESS = 2;
    private static final int CHECK_CARD_MAG = 3;
    private static final int CHECK_CARD_NFC = 4;
    private static final int CHECK_CARD_IC = 5;

    private Looper mLooper = Looper.getMainLooper();
    private final Handler mHandler = new Handler(mLooper) {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CHECK_CARD_FAIL:
                    dismissLoadingDialog();
                    String hint = (String) msg.obj;
                    checkCardFail(msg.arg1, hint);
                    break;
                case CHECK_CARD_SUCCESS:
                    getCardInfo();
                    getF055Data();
                    callbackSuccess();
                    break;
                case CHECK_CARD_MAG:
                    Bundle bundle = (Bundle) msg.obj;
                    handleMagCard(bundle);
                    break;
                case CHECK_CARD_NFC:
                    handleNFCCard();
                    break;
                case CHECK_CARD_IC:
                    handleICCard();
                    break;
            }
        }

    };

    public void startCheckCard() {
        try {
            mReadCardOptV2.checkCard(mCheckCardType, mReadCardCallback, 60);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void abortCheckCard() {
        try {
            mReadCardOptV2.cancelCheckCard();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置消费金额
     */
    public void setAmount(long amount) {
        mTradeData.getPayDetail().setAmount(amount);
    }

    /**
     * 设置检卡类型
     */
    public void setCheckCardType(int cardType) {
        mCheckCardType = cardType;
    }

    private void setTerminalParam() {
        try {
            EmvTermParamV2 emvTermParam = new EmvTermParamV2();
            emvTermParam.capability = "E0F8C8";
            emvTermParam.countryCode = "0458";
            int result = mEMVOptV2.setTerminalParam(emvTermParam);
            LogUtil.e(Constant.TAG, "setTerminalParam result:" + result);
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.e(Constant.TAG, "setTerminalParam fail");
        }
    }

    private void handleCallProgram(L3ErrorCode code) {
        if (Params.sL3Params == null) return;
        sendCloseAppBroadcast();
        L3BroadcastHelper.sendFailedBroadcast(this, code);
    }

    private CheckCardCallbackV2 mReadCardCallback = new CheckCardCallbackV2.Stub() {

        @Override
        public void findMagCard(Bundle bundle) throws RemoteException {
            LogUtil.e(Constant.TAG, "findMagCard");
            mPayDetail.cardType = CardType.MAGNETIC.getValue();
            mHandler.obtainMessage(CHECK_CARD_MAG, bundle).sendToTarget();
        }

        @Override
        public void findRFCard(String uuid) throws RemoteException {
            LogUtil.e(Constant.TAG, "findRFCard:" + uuid);
            mPayDetail.cardType = CardType.NFC.getValue();
            mHandler.obtainMessage(CHECK_CARD_NFC).sendToTarget();
        }

        @Override
        public void findICCard(String atr) throws RemoteException {
            LogUtil.e(Constant.TAG, "findICCard:" + atr);
            mPayDetail.cardType = CardType.IC.getValue();
            mHandler.obtainMessage(CHECK_CARD_IC).sendToTarget();
        }

        @Override
        public void onError(int code, String msg) throws RemoteException {
            LogUtil.e(Config.TAG, "onError code:" + code + " msg:" + msg);
            mHandler.obtainMessage(CHECK_CARD_FAIL, code, code, msg).sendToTarget();
        }

    };

    private void handleMagCard(Bundle bundle) {
        String track1 = bundle.getString("TRACK1");
        String track2 = bundle.getString("TRACK2");
        String track3 = bundle.getString("TRACK3");
        // 根据一磁 获取 持卡人姓名
        if (track1 != null && track1.length() > 0) {
            String[] split = track1.split("\\^");
            if (split.length >= 2) {
                String cardHolderName = split[1];
                LogUtil.e(Config.TAG, "cardHolderName:" + cardHolderName);
                mPayDetail.cardHolderName = cardHolderName;
            }
        }
        CardInfo cardInfo = Track2Util.parseTrack2(track2);
        cardInfo.track1 = track1;
        cardInfo.track2 = track2;
        cardInfo.track3 = track3;
        cardInfo.cardType = CardType.MAGNETIC.getValue();
        if (cardInfo.cardNo != null && cardInfo.cardNo.length() >= 13 && cardInfo.cardNo.length() <= 19) {
            mTradeData = KernelDataProcessUtil.fillTradeDataInfo(cardInfo, mTradeData);
            callbackSuccess();
        } else {
            startCheckCard();
        }
    }

    private void handleNFCCard() {
        showLoadingDialog(R.string.swing_carding);
        // transactProcess();
        callbackSuccess();
    }

    private void handleICCard() {
        // 是否强制非接
        boolean isForceNFC = TransactionOtherOperation.getInstance().getTransactionOtherSettings().isForceNFC();
        if (isForceNFC) {
            showForceNFCWarningDialog();
            startCheckCard();
        } else {
            showLoadingDialog(R.string.swing_carding);
            // transactProcess();
            callbackSuccess();
        }
    }

    private void initEmvProcess() {
        try {
            // 设置普通的TLV数据
            String[] tags = {"5F2A", "5F36"};
            String[] values = {"0643", "00"};
            mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tags, values);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void transactProcess() {
        LogUtil.e(Constant.TAG, "***************************************************************");
        LogUtil.e(Constant.TAG, "****************************Start Process**********************");
        LogUtil.e(Constant.TAG, "***************************************************************");

        LogUtil.e(Constant.TAG, "transactProcess");
        try {
            // 初始化EMV流程
            mEMVOptV2.initEmvProcess();

            EMVTransDataV2 emvTransData = new EMVTransDataV2();
            emvTransData.amount = mPayDetail.amount + "";
            emvTransData.flowType = 2; // 简易流程
            emvTransData.cardType = mPayDetail.cardType;
            mEMVOptV2.transactProcess(emvTransData, mEMVListener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void callbackSuccess() {
        dismissLoadingDialog();
        dismissForceNFCWarningDialog();
        onCheckCardSuccess();
    }

    private void checkCardFail(int code, String msg) {
        // 检卡超时
        if (AidlErrorCode.READ_CARD_TIMEOUT.getCode() == code) {
            showToast(msg);
            handleCallProgram(L3ErrorCode.ERROR_TRADE_TIMEOUT);
            finish();
            return;
        }

        if (SPErrorCode.EMV_TRY_ANOTHER_INTERFACE.getCode() == code) {
            showToast(R.string.swing_card_amount_out);
            // 金额超限 去掉NFC
            mCheckCardType = CardType.IC.getValue() | CardType.MAGNETIC.getValue();
        } else if (AidlErrorCode.READ_CARD_FALLBACK.getCode() == code) {
            LogUtil.e(Config.TAG, "此卡为芯片卡，不可降级交易");
            showToast(msg);
        } else {
            boolean b = code == SPErrorCode.CLS_TYPEA_ERR_NUMBER.getCode() ||
                    code == SPErrorCode.CLS_HAL_ERR_TIMEOUT.getCode() ||
                    code == SPErrorCode.CLS_HAL_ERR_CRC.getCode() ||
                    code == SPErrorCode.ENDAPPLICATION_CMD_ERR.getCode() ||
                    code == SPErrorCode.EMV_ENDAPPLICATION.getCode();
            if (b) {
                // TODO 屏蔽-4100 -2520 -2526 -4002 -2540 非接刷卡错误
            } else {
                showToast(msg);
            }
        }

        startCheckCard();
    }

    private void showForceNFCWarningDialog() {
        if (mForceNFCWarningDialog == null) {
            mForceNFCWarningDialog = new ForceNFCWarningDialog(this);
            mForceNFCWarningDialog.setOwnerActivity(this);
        }
        boolean b = mForceNFCWarningDialog.isShowing() || isDestroyed();
        if (b) return;
        try {
            mForceNFCWarningDialog.show();
            mForceNFCWarningDialog.dismissDelayed(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void dismissForceNFCWarningDialog() {
        if (mForceNFCWarningDialog != null) {
            try {
                mForceNFCWarningDialog.dismiss();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private EMVListenerV2 mEMVListener = new EMVListenerV2.Stub() {

        @Override
        public void onWaitAppSelect(List<EMVCandidateV2> appNameList, boolean isFirstSelect) throws RemoteException {
            LogUtil.e(Constant.TAG, "onWaitAppSelect isFirstSelect:" + isFirstSelect);
            showListDialog(appNameList);
        }

        @Override
        public void onAppFinalSelect(String tag9F06Value) throws RemoteException {
            LogUtil.e(Constant.TAG, "tag9F06Value:" + tag9F06Value);
            initEmvProcess();
            if (tag9F06Value != null && tag9F06Value.length() > 0) {
                boolean visa = tag9F06Value.startsWith("A000000003");
                boolean master = tag9F06Value.startsWith("A000000004");
                boolean unionPay = tag9F06Value.startsWith("A000000333");
                if (visa) {
                    // VISA(PayWave)
                    LogUtil.e(Constant.TAG, "detect VISA card");
                    String[] tagsPayWave = {
                            "DF8124", "DF8125", "DF8126"
                    };
                    String[] valuesPayWave = {
                            "999999999999", "999999999999", "000000000000"
                    };
                    mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYWAVE, tagsPayWave, valuesPayWave);
                } else if (master) {
                    // MasterCard(PayPass)
                    LogUtil.e(Constant.TAG, "detect MasterCard card");
                    String[] tagsPayPass = {
                            "DF8117", "DF8118", "DF8119", "DF811F", "DF811E", "DF812C",
                            "DF8123", "DF8124", "DF8125", "DF8126",
                            "DF811B", "DF811D",
                    };
                    String[] valuesPayPass = {
                            "E0", "F8", "F8", "E8", "00", "00",
                            "999999999999", "999999999999", "999999999999", "000000000000",
                            "30", "02"
                    };
                    mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagsPayPass, valuesPayPass);
                } else if (unionPay) {
                    // UnionPay
                    LogUtil.e(Constant.TAG, "detect UnionPay card");
                }
            }
            mEMVOptV2.importAppFinalSelectStatus(0);
        }

        @Override
        public void onConfirmCardNo(String cardNo) throws RemoteException {
            LogUtil.e(Constant.TAG, "onConfirmCardNo cardNo:" + cardNo);
            mEMVOptV2.importCardNoStatus(0);
        }

        @Override
        public void onRequestShowPinPad(int type, int remainTime) throws RemoteException {
            LogUtil.e(Config.TAG, "requestShowPinPad type:" + type + " remainTime:" + remainTime);
            mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
        }

        @Override
        public void onRequestSignature() throws RemoteException {
            LogUtil.e(Constant.TAG, "signatureStatus");
            mEMVOptV2.importSignatureStatus(0);
        }

        @Override
        public void onCertVerify(int certType, String certInfo) throws RemoteException {
            LogUtil.e(Constant.TAG, "onCertVerify certType:" + certType + " certInfo:" + certInfo);
            mEMVOptV2.importCertStatus(0);
        }

        @Override
        public void onOnlineProc() throws RemoteException {
            LogUtil.e(Config.TAG, "onProcessEnd");
            mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
        }

        @Override
        public void onCardDataExchangeComplete() throws RemoteException {
            LogUtil.e(Config.TAG, "onCardDataExchangeComplete");
        }

        @Override
        public void onConfirmationCodeVerified() throws RemoteException {
            LogUtil.e(Config.TAG, "onConfirmationCodeVerified");
        }

        @Override
        public void onTransResult(int code, String desc) throws RemoteException {
            if (code != 0) {
                mHandler.obtainMessage(CHECK_CARD_FAIL, code, code, desc).sendToTarget();
            } else {
                mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
            }
            LogUtil.e(Constant.TAG, "onTransResult code:" + code + " desc:" + desc);
            LogUtil.e(Constant.TAG, "***************************************************************");
            LogUtil.e(Constant.TAG, "****************************End Process************************");
            LogUtil.e(Constant.TAG, "***************************************************************");
        }

    };

    private void getCardInfo() {
        String[] tagList = {"5A", "5F24", "57", "5F34"};
        byte[] outData = new byte[1024];
        try {
            int len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagList, outData);
            if (len > 0) {
                byte[] data = new byte[len];
                System.arraycopy(outData, 0, data, 0, len);
                CardInfo cardInfo = KernelDataProcessUtil.getCardInfo(mPayDetail.cardType, data);
                mTradeData = KernelDataProcessUtil.fillTradeDataInfo(cardInfo, mTradeData);
            } else {
                LogUtil.e(Configs.TAG, "获取卡片信息的数据长度为负数 = " + len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void getF055Data() {
        String[] tagList = {"DF02", "5F34", "9F06", "FF30", "FF31", "95", "9B",
                "9F36", "9F26", "9F27", "DF31", "5A", "57", "5F24", "9F1A", "9F03", "9F33",
                "9F10", "9F37", "9C", "9A", "9F02", "5F2A", "82", "9F34", "9F35", "9F1E",
                "84", "4F", "9F09", "9F41", "9F63", "50", "9F08", "9F0E", "9F0F", "9F0D"};
        byte[] outData = new byte[2048];
        try {
            int len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagList, outData);
            if (len > 0) {
                byte[] data = new byte[len];
                System.arraycopy(outData, 0, data, 0, len);
                mTradeData = KernelDataProcessUtil.readKernelData(data, mTradeData);
            } else {
                LogUtil.e(Configs.TAG, "获取55域的数据长度为负数 = " + len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getNonContactFreeData() {
        String[] tagList = {"9F6C", "9F51", "DF71", "4F",};
        byte[] outData = new byte[1024];
        try {
            int len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagList, outData);
            if (len > 0) {
                byte[] data = new byte[len];
                System.arraycopy(outData, 0, data, 0, len);
                mTradeData = KernelDataProcessUtil.readNonContactFreeData(data, mTradeData);
            } else {
                LogUtil.e(Configs.TAG, "获取qps数据的数据长度为负数 = " + len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void showListDialog(List<EMVCandidateV2> list) {
        runOnUI(
                () -> {
                    if (mListDialog == null) {
                        mListDialog = new ListDialog(this);
                        mListDialog.setTitleText(R.string.index_select_app);
                        mListDialog.setCancelable(true);
                        mListDialog.setCanceledOnTouchOutside(true);
                    }
                    List<String> tempList = new ArrayList<>();
                    for (EMVCandidateV2 emvCandidateV2 : list) {
                        tempList.add(emvCandidateV2.aid);
                    }
                    mListDialog.setData(tempList);
                    mListDialog.setOnItemClickListener(
                            position -> {
                                try {
                                    mEMVOptV2.importAppSelect(position);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                    );
                    try {
                        mListDialog.show();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
        );
    }

    private void dismissListDialog() {
        if (mListDialog != null) {
            mListDialog.dismiss();
        }
    }


}
